package mythread;

/**
 * @Auther: cty
 * @Date: 2020/1/12 14:23
 * @Description: DCL（Double Checking Locking）实现单例模式：懒汉式套路基础上加入并发控制，保证在多线程环境下，对外存在一个对象
 * 1、构造器私有化——>避免外部new构造器
 * 2、提供私有静态属性——>存储对象的地址
 * 3、提供公共的静态方法——>获取属性
 * @version: 1.0
 */
public class Je_Other_SingletonMode {
    //2、提供私有静态属性——>存储对象的地址
    private static volatile Je_Other_SingletonMode instance;
    //没有volatile其他线程可能会访问到一个还未初始化的对象

    //1、构造器私有化——>避免外部new构造器
    private Je_Other_SingletonMode(){

    }

    //3、提供公共的静态方法——>获取属性
    public static Je_Other_SingletonMode getInstance(){
        //Doubl Checking  避免不必要的同步
        if(null!=instance){
            return instance;
        }
        synchronized(Je_Other_SingletonMode.class){  //锁定类的模子
            if(null==instance){
                instance = new Je_Other_SingletonMode();  //创建对象需要时间，为避免a访问时还没创建完，b访问时重复创建，因此需要锁定
                //1 开辟空间  2 初始化对象信息  3 返回对象的地址给引用
                //由于初始化时间可能比较长，可能会出现指令重排——还未初始化结束，就已经返回对象的地址给引用
                //存在问题：此时引用获取的地址可能为空！
            }
        }
        return instance;
    }

    public static Je_Other_SingletonMode getInstance1(long time){
        if(null==instance){
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Je_Other_SingletonMode();  //创建对象需要时间，为避免a访问时还没创建完，b访问时重复创建，因此需要锁定
            //1 开辟空间  2 初始化对象信息  3 返回对象的地址给引用
            //由于初始化时间可能比较长，可能会出现指令重排——还未初始化结束，就已经返回对象的地址给引用
            //存在问题：此时引用获取的地址可能为空！
        }
        return instance;
    }

    public static void main(String[] args) {
        //经过同步，地址相同
//        Thread t = new Thread(()->{
//            System.out.println(Je_Other_SingletonMode.getInstance());
//        });
//        t.start();
//        System.out.println(Je_Other_SingletonMode.getInstance());

        //无同步，地址不一样
        Thread t1 = new Thread(()->{
           System.out.println(Je_Other_SingletonMode.getInstance1(100));
        });
        t1.start();
        System.out.println(Je_Other_SingletonMode.getInstance1(100));
    }
}
